/*
 * Copyright (c) 2020, HiHope Community.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifi_device.h"
#include "lwip/netifapi.h"
#include "lwip/api_shell.h"

#include "connect_wifi.h"
#include "oled.h"

connect_wifi_data_t connect_wifi_data;

int netId = -1;
WifiErrorCode errCode;
static struct netif* iface = NULL;

WifiEvent eventListener;

static void PrintLinkedInfo(WifiLinkedInfo* info);
static void OnWifiConnectionChanged(int state, WifiLinkedInfo* info);
static void OnWifiScanStateChanged(int state, int size);

err_t netifapi_set_hostname(struct netif *netif, char *hostname, u8_t namelen);


static void PrintLinkedInfo(WifiLinkedInfo* info)
{
    if (!info) return;

    static char macAddress[32] = {0};
    unsigned char* mac = info->bssid;
    snprintf(macAddress, sizeof(macAddress), "%02X:%02X:%02X:%02X:%02X:%02X",
        mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    printf("bssid: %s, rssi: %d, connState: %d, reason: %d, ssid: %s\r\n",
        macAddress, info->rssi, info->connState, info->disconnectedReason, info->ssid);
}


static void OnWifiConnectionChanged(int state, WifiLinkedInfo* info)
{
    if (!info) return;

    printf("%s %d, state = %d, info = \r\n", __FUNCTION__, __LINE__, state);
    PrintLinkedInfo(info);

    if (state == WIFI_STATE_AVALIABLE)
    {
        connect_wifi_data.wifi_connect_state = 1;
    }
    else
    {
        connect_wifi_data.wifi_connect_state = 0;
    }
}


static void OnWifiScanStateChanged(int state, int size)
{
    printf("%s %d, state = %X, size = %d\r\n", __FUNCTION__, __LINE__, state, size);
}

//
int connect_to_wifi(void)
{
    connect_wifi_data.wifi_connect_state = 0;
    connect_wifi_data.last_wifi_connect_state = 0;
    
    uint8_t Connecting[] = {"Connecting wifi..."};
    uint8_t time_out[]   = {"wifi time out"};
    uint8_t Connected[] = {"wifi had connected."};

    int timeout = 50;
    WifiDeviceConfig apConfig = {};

    eventListener.OnWifiConnectionChanged = OnWifiConnectionChanged;
    eventListener.OnWifiScanStateChanged  = OnWifiScanStateChanged;
    OLED_Clear_Line(1);
    OLED_Show_String(0, 1, 8, Connecting);
    osDelay(10);
    errCode = RegisterWifiEvent(&eventListener);
    printf("RegisterWifiEvent: %d\r\n", errCode);

    // setup your AP params
    strcpy(apConfig.ssid, PARAM_HOTSPOT_SSID);
    strcpy(apConfig.preSharedKey, PARAM_HOTSPOT_PSK);
    apConfig.securityType = WIFI_SEC_TYPE_PSK;

    errCode = EnableWifi();
    printf("EnableWifi: %d\r\n", errCode);
    osDelay(10);

    errCode = AddDeviceConfig(&apConfig, &netId);
    printf("AddDeviceConfig: %d\r\n", errCode);

    errCode = ConnectTo(netId);
    printf("ConnectTo(%d): %d\r\n", netId, errCode);

    while (!connect_wifi_data.wifi_connect_state)    //timeout = 5s
    {
        osDelay(10);
        timeout--;
        if(timeout == 0)
        {
            OLED_Clear_Line(1);
            OLED_Show_String(0, 1, 8, time_out);
            oled_clear_line(0, 0, 0, 7);
            disconnect_With_wifi();    //连接超时先关闭wifi，不然底层会一直去连接，即使这里退出了。
            break;
        }
    }
    if(connect_wifi_data.wifi_connect_state == 1)
    {
        OLED_Clear_Line(1);
        OLED_Show_String(0, 1, 8, Connected);

        osDelay(50);
        iface = netifapi_netif_find("wlan0");
        
        if (iface) 
        {
            err_t ret = 0;
            char* hostname = "HarmnoyOS";
            ret = netifapi_set_hostname(iface, hostname, strlen(hostname));
            printf("netifapi_set_hostname: %d\r\n", ret);

            ret = netifapi_dhcp_start(iface);
            printf("netifapi_dhcp_start: %d\r\n", ret);

            osDelay(200); // wait DHCP server give me IP
            ret = netifapi_netif_common(iface, dhcp_clients_info_show, NULL);
            printf("netifapi_netif_common: %d\r\n", ret);
        }
    }
    return 0;
}

void disconnect_With_wifi(void)
{

    eventListener.OnWifiConnectionChanged = OnWifiConnectionChanged;
    eventListener.OnWifiScanStateChanged  = OnWifiScanStateChanged;

    if (iface)
    {
        netifapi_dhcp_stop(iface);
        //err_t ret = netifapi_dhcp_stop(iface);
        //printf("netifapi_dhcp_stop: %d\r\n", ret);
    }

    Disconnect();
    //WifiErrorCode errCode = Disconnect(); // disconnect with your AP
    //printf("Disconnect: %d\r\n", errCode);
    UnRegisterWifiEvent(&eventListener);
    //errCode = UnRegisterWifiEvent(&eventListener);
    //printf("UnRegisterWifiEvent: %d\r\n", errCode);

    RemoveDevice(netId); // remove AP config
    //printf("RemoveDevice: %d\r\n", errCode);
    DisableWifi();
    //errCode = DisableWifi();
    //printf("DisableWifi: %d\r\n", errCode);

}
